package com.simpou.commons.utils.cipher;

import java.io.UnsupportedEncodingException;

import java.math.BigInteger;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


/**
 * Trata das operacoes sobre encriptação de textos. Utiliza codificação UTF-8
 * e algoritmo PBEWithMD5AndDES.
 *
 * @author Jonas Pereira
 * @since 2008-06-20
 * @version 2012-05-15
 */
public class Encryptor {
    /**
     * Número máximo de caracteres da chave.
     */

    //public static final int MAX_KEY_LENGTH = 15;

    /**
     * Algoritmo Blowfish.
     */

    //public static final String ALG_BLOWFISH = "Blowfish";

    /**
     * Algoritmo DES.
     */

    //public static final String ALG_DES = "DES";

    /**
     * Algoritmo DESede.
     */

    //public static final String ALG_DESEDE = "DESede";

    /**
     * Algoritmo PBEWithMD5AndDES.
     */

    //public static final String ALG_PBE_MD5_DES = "PBEWithMD5AndDES";

    /**
     * Algoritmo PBEWithMD5AndTripleDES.
     */

    //public static final String ALG_PBE_MD5_TRIPLE_DES = "PBEWithMD5AndTripleDES";

    /**
     * Algoritmo TripleDES.
     */

    //public static final String ALG_TRIPLE_DES = "TripleDES";

    /**
     * Algoritmo padrão usado para criptografia.
     */

    //private static final String DEFAULT_ALGORITHM = ALG_PBE_MD5_DES;

    /**
     * Codificação de caracteres utilizada.
     */
    private static final String DEFAULT_CHARSET_NAME = "UTF8";

    /**
     * Digest MD5.
     */
    private static final MessageDigest mdMD5 = MessageDigests.getDigest(
            "MD5");

    /**
     * Cipher encriptador.
     */

    //private final Cipher ecipher;

    /**
     * Cipher decriptador.
     */

    //private final Cipher dcipher;

    /**
     * Constructor used to create this object.  Responsible for setting
     * and initializing this object's encrypter and decrypter Chipher instances
     * given a Secret Key and algorithm.
     *
     * @param key        Secret Key used to initialize both the encrypter and
     *                   decrypter instances.
     * @param algorithm  Which algorithm to use for creating the encrypter and
     *                   decrypter instances.
     * @throws java.security.NoSuchAlgorithmException java.security.NoSuchAlgorithmException.
     * @throws javax.crypto.NoSuchPaddingException javax.crypto.NoSuchPaddingException.
     * @throws java.security.InvalidKeyException java.security.InvalidKeyException.
     */

    /*    public CryptHelper(final SecretKey key, final String algorithm)
            throws NoSuchAlgorithmException, NoSuchPaddingException,
                InvalidKeyException {
            this.ecipher = Cipher.getInstance(algorithm);
            this.ecipher.init(Cipher.ENCRYPT_MODE, key);
            this.dcipher = Cipher.getInstance(algorithm);
            this.dcipher.init(Cipher.DECRYPT_MODE, key);
        }
    */

    /**
     * Usa algoritmo PBEWithMD5AndDES e codifiação UTF-8.
     *
     * @param key Chave de criptografia a ser utilizada. Deve conter no máximo 15 caracteres.
     * @throws java.lang.Exception java.lang.Exception.
     */

    /*    public CryptHelper(final String key) throws Exception {
            if ((key == null) || (key.length() < 1)) {
                throw new IllegalArgumentException("Key cannot be null.");
            }
    
            if (key.length() > MAX_KEY_LENGTH) {
                throw new IllegalArgumentException("Key length greater then max: " +
                    MAX_KEY_LENGTH);
            }
    
            // 8-bytes Salt
            byte[] salt = {
                    (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
                    (byte) 0x34, (byte) 0xE3, (byte) 0x03
                };
    
            // Iteration count
            int iterationCount = 19;
            KeySpec keySpec = new PBEKeySpec(key.toCharArray(), salt, iterationCount);
            SecretKey secretKey = SecretKeyFactory.getInstance(DEFAULT_ALGORITHM)
                                                  .generateSecret(keySpec);
    
            ecipher = Cipher.getInstance(secretKey.getAlgorithm());
            dcipher = Cipher.getInstance(secretKey.getAlgorithm());
    
            // Prepare the parameters to the cipthers
            AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt,
                    iterationCount);
    
            ecipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
            dcipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
        }
    */

    /**
     * Takes a single String as an argument and returns an Encrypted version
     * of that String.
     *
     * @param str String to be encrypted
     * @return <code>String</code> Encrypted version of the provided String
     * @throws java.lang.Exception java.lang.Exception.
     */

    /*    public String crypt(final String str) throws Exception {
            if (str == null) {
                return null;
            }
    
            // Encode the string into bytes using
            byte[] decrypted = str.getBytes(DEFAULT_CHARSET_NAME);
    
            // Encrypt
            byte[] enc = ecipher.doFinal(decrypted);
    
            // Encode bytes to base64 to get a string
            return new sun.misc.BASE64Encoder().encode(enc);
        }
    */

    /**
     * Takes a encrypted String as an argument, decrypts and returns the
     * decrypted String.
     *
     * @param str Encrypted String to be decrypted
     * @return <code>String</code> Decrypted version of the provided String
     * @throws java.lang.Exception java.lang.Exception.
     */

    /*    public String decrypt(final String str) throws Exception {
            // Decode base64 to get bytes
            byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
    
            // Decrypt
            byte[] decrypted = dcipher.doFinal(dec);
    
            // Decode using utf-8
            return new String(decrypted, DEFAULT_CHARSET_NAME);
        }
    */

    /**
     * <p>cryptMD5.</p>
     *
     * @param text Texto a ser encriptado.
     * @return Texto encriptado MD5.
     * @throws java.security.NoSuchAlgorithmException Algoritmo MD5 não encontrado.
     * @throws java.io.UnsupportedEncodingException Charset padrão não suportado.
     */
    public static synchronized String cryptMD5(final String text)
        throws NoSuchAlgorithmException, UnsupportedEncodingException {
        if (text == null) {
            return null;
        }

        BigInteger hash = new BigInteger(1,
                mdMD5.digest(text.getBytes(DEFAULT_CHARSET_NAME)));
        String s = hash.toString(16);

        // não lembro por que coloquei isso aqui        
        //        if (NumberHelper.isEven(s.length())) {
        //            s = "0" + s;
        //        }
        return s;
    }

    /**
     * <p>cryptSHA256.</p>
     *
     * @param text Texto a ser encriptado.
     * @return Texto encriptado com algoritmo SHA256
     * @throws java.security.NoSuchAlgorithmException Algoritmo SHA256 não encontrado.
     * @throws java.io.UnsupportedEncodingException Codificação UTF-8 não suportada.
     */
    public static synchronized String cryptSHA256(final String text)
        throws NoSuchAlgorithmException, UnsupportedEncodingException {
        if (text == null) {
            return null;
        } else {
            return Hashs.getHash(text);
        }
    }
}
